/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package quan;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JDesktopPane;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.Scrollable;
import javax.swing.TransferHandler;
import javax.swing.UIManager;

/**
 *
 * @author Quannk
 */
public class QDesktopPane extends JDesktopPane implements Scrollable {

    private final double SCALE = 0.5;
    private JPopupMenu popupMenu;
    private QOverviewPanel overviewPanel;
    Point foldPoint;
    QLine currentLine;
    boolean flag;
    boolean isJoin;
    Point endPoint;
    Vector<QInternalFrame> qInternalFrames = new Vector<>();
    Vector<QLine> qLines = new Vector<>();
    private boolean isStartNewLine;
    private QInternalFrame startNewLineFrame;

    public boolean getIsStartNewLine() {
        return isStartNewLine;
    }

    public void setIsStartNewLine(boolean isStartNewLine) {
        this.isStartNewLine = isStartNewLine;
    }

    public void setOverviewPanel(QOverviewPanel overviewPanel) {
        this.overviewPanel = overviewPanel;
    }

    public QOverviewPanel getOverviewPanel() {
        return overviewPanel;
    }
    QScrollPane scrollPane;

    public QDesktopPane(QScrollPane scrollPane) {
        this.scrollPane = scrollPane;
        initPopupMenu();
        setDoubleBuffered(true);
        initMouseListener();
        initComponentListener();
        initTransferHandler();
    }

    private void initPopupMenu() {
        popupMenu = new JPopupMenu("Menu");
        JMenuItem mniAdd = new JMenuItem("Add");
        popupMenu.add(mniAdd);
        mniAdd.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addQInternalFrame(false, null);
            }
        });
        JMenuItem mniSort1 = new JMenuItem("Horizontal");
        popupMenu.add(mniSort1);
        mniSort1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                performLayout(QLayout.Orientation.Horizontal);
            }
        });
        JMenuItem mniSort2 = new JMenuItem("Vertical");
        popupMenu.add(mniSort2);
        mniSort2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                performLayout(QLayout.Orientation.Vertical);
            }
        });
    }

    private void performLayout(QLayout.Orientation orientation) {
        for (QLine line : qLines) {
            line.removeAllFoldPoint();
        }
        QLayout layout = new QLayout(this);
        layout.performLayout(orientation);
        if (overviewPanel != null) {
            overviewPanel.repaint();
        }
    }

    public QInternalFrame addQInternalFrame(boolean isFromInternal, String title) {
        int count = qInternalFrames.size() + 1;        
        QInternalFrame frame = new QInternalFrame("Frame " + count);
        if (title != null) {
            frame.setTitle(title);
        }
        frame.setBounds(20 * count, 20 * count, 150, 100);
        frame.setVisible(true);
        Point p = new Point();
        p.x = 20 * count + frame.getWidth() / 2;
        p.y = 20 * count + frame.getHeight() / 2;
        frame.setSelectedPoint(p);
        qInternalFrames.addElement(frame);
        frame.level = 1;
        if (isFromInternal) {
            QInternalFrame parentFrame = (QInternalFrame) getSelectedFrame();
            QLine line = new QLine(parentFrame, frame);
            qLines.addElement(line);
            frame.level = parentFrame.level + 1;
            frame.parentFrame = parentFrame;
        }
        add(frame);
        try {
            frame.setSelected(true);
        } catch (PropertyVetoException ex) {
            Logger.getLogger(QDesktopPane.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (overviewPanel != null) {
            overviewPanel.repaint();
        }
        return frame;
    }

    public void removeQInternalFrame(QInternalFrame frame) {
        List<QLine> deleteLines = new ArrayList<>();
        for (QLine line : qLines) {
            if (line.containFrame(frame)) {
                deleteLines.add(line);
            }
        }
        qLines.removeAll(deleteLines);

        qInternalFrames.remove(frame);
        remove(frame);
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        for (QLine line : qLines) {
            line.drawLine(g);
        }
        if (isStartNewLine && endPoint != null) {
            int x1 = ((QInternalFrame) getSelectedFrame()).selectedPoint.x;
            int y1 = ((QInternalFrame) getSelectedFrame()).selectedPoint.y;

            g.drawLine(x1, y1, endPoint.x, endPoint.y);
        }
    }

    public void updatePointWhenMove(QInternalFrame frame) {
        for (QLine line : qLines) {
            if (line.containFrame(frame)) {
                line.updatePoint(frame);
            }
        }
        if (overviewPanel != null) {
            overviewPanel.repaint();
        }
    }

    @Override
    public Dimension getPreferredScrollableViewportSize() {
        return getPreferredSize();
    }

    @Override
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
        return 50;
    }

    @Override
    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
        return 200;
    }

    @Override
    public boolean getScrollableTracksViewportWidth() {
        return false;
    }

    @Override
    public boolean getScrollableTracksViewportHeight() {
        return false;
    }

    public void synchronizedScroll(Point p) {
        scrollPane.setSynchronizedScroll(true);
        double scaleX = scrollPane.getViewport().getViewSize().getWidth() / getPreferredSize().getWidth();
        double scaleY = scrollPane.getViewport().getViewSize().getHeight() / getPreferredSize().getHeight();
        p.x = (int) (p.x / scaleX);
        p.y = (int) (p.y / scaleY);
        scrollPane.getViewport().setViewPosition(p);
    }

    private void initMouseListener() {
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                if (isStartNewLine) {
                    endPoint = e.getPoint();
                    repaint();
                    return;
                }
                if (foldPoint != null) {
                    int index = currentLine.points.indexOf(foldPoint);
                    currentLine.points.set(index, e.getPoint());
                    repaint();
                    foldPoint = e.getPoint();
                }
            }
        });
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if (e.getButton() == MouseEvent.BUTTON3) {
                    popupMenu.show(QDesktopPane.this, e.getX(), e.getY());
                }
                if (e.getButton() == MouseEvent.BUTTON1) {
                    if (foldPoint != null) {
                        foldPoint = null;
                        return;
                    }
                    for (QLine line : qLines) {
                        foldPoint = line.getFoldPoint(e.getPoint());
                        if (foldPoint != null) {
                            currentLine = line;
                            break;
                        }
                        if (line.addFoldPoint(e.getPoint())) {
                            repaint();
                            break;
                        }

                    }
                }
            }
        });
    }

    public QOverviewPanel createOverview() {
        QOverviewPanel ovp = new QOverviewPanel();
        ovp.setDesktopPane(this);
        int w, h;
        w = (int) (getPreferredSize().width * SCALE);
        h = (int) (getPreferredSize().height * SCALE);
        ovp.setPreferredSize(new Dimension(w, h));
        ovp.setSize(w, h);
        return ovp;
    }

    private void initComponentListener() {
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                super.componentResized(e);
                if (overviewPanel != null) {
                    overviewPanel.setVisibleRect(scrollPane.getViewport().getViewRect());
                }
            }
        });
    }

    private void initTransferHandler() {
        setTransferHandler(new TransferHandler() {
            @Override
            public boolean canImport(TransferHandler.TransferSupport support) {
                boolean result;
                result = support.isDataFlavorSupported(DataFlavor.stringFlavor);
                return result;
            }

            @Override
            public boolean importData(TransferHandler.TransferSupport support) {
                boolean result = false;
                if (!support.isDrop()) {
                    return false;
                }
                if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    return false;
                }

                Transferable t = support.getTransferable();
                try {
                    String data = (String) t.getTransferData(DataFlavor.stringFlavor);
                    addQInternalFrame(false, data);
                } catch (UnsupportedFlavorException | IOException ex) {
                    return false;
                }

                return result;
            }
        });
    }

    void startNewLine(QInternalFrame f) {
        isStartNewLine = true;
        startNewLineFrame = f;
    }

    public QInternalFrame getStartNewLineFrame() {
        return startNewLineFrame;
    }
    
    void createNewLine(QInternalFrame start, QInternalFrame end)
    {
        for (QLine line : qLines) {
            if(line.containFrame(start) && line.containFrame(end))
                return;
        }
        QLine line = new QLine(start, end);
        qLines.add(line);
        isStartNewLine = false;
        repaint();
    }
}
